#include "Person.h"
#include "xtraits.h"
//#include "ALua.h"
//#include "ALuaEx.h"
int func(int a) {
	printf("calling func, input: %d\n", a);
	return a;
}

void noRet() {}

Person* CreatePerson()
{
	return new Person();
}

Person* CreateStudent()
{
	return new Student();
}

void ModifyPerson(Person& p)
{
	p.age = 55;
}

void PrintAnyType(const SReflect::Any a)
{
	std::cout << *a.get_type() << std::endl;
}

int global_data = 45;

Reflect_Method(func);
Reflect_Field(global_data);



//EXPORT_GLOBAL_FUNCTION(int,func,int);
//EXPORT_GLOBAL_FUNCTION(Person*,CreatePerson);
//EXPORT_GLOBAL_FUNCTION(Person*, CreateStudent);
//EXPORT_GLOBAL_FUNCTION(void, ModifyPerson, Person&);
//EXPORT_GLOBAL_FIELD(int, global_data);
int main()
{
	using namespace SReflect;
	using Any = SReflect::Any;
	Any anyStr = std::string("Allen");
	try
	{
		int a = anyStr.cast<int>();
	}
	catch (const std::exception& exp)
	{
		std::cout << exp.what() << std::endl;
	}
	if (std::string* a = anyStr.try_cast<std::string>())
	{
		std::cout << "value is " << *a << std::endl;
	}
	try {
		Any tmpAny = Person{};
		PrintAnyType(std::move(tmpAny));
		Person p;
		p.age = 26;
		p.name = "allen";
		p.height = 1.81;
		printf("original Person variable P:\n");
		p.show();
		printf("Any get a copy of P, named a. modify a's age:\n");
		Any a = make_any_copy(p);
		a.set_member_data("age", 24u);
		a.call_member_function("show");
		printf("Any get a ref of P, named b. modify b's name:\n");
		Any b = make_any_ref(p);
		b.set_member_data("name", std::string("kitty"));
		b.call_member_function("show");
		printf("after modify b's name, original P is:\n");
		p.show();
		printf("get b's field age, named c. modify c to 18. original P is:\n");
		Any c = b.get_member_data("age");
		c = 18;
		Any d;
		d = c;
		p.show();
		MaleStudent ms;
		Any e = make_any_ref(ms);
		printf("create MaleStudent, ref it as e:\n");
		e.call_member_function("show");
		Any f = e.get_member_data("id");
		const int tmp = 1024;
		f = tmp;
		e["age"] = 24;
		e["count"] = 102;
		printf("assign Person::count to: %d\n", Person::count);
		printf("f index e[school]\n");
		f = e.get_member_data("school");
		f = std::string("jiao tong university");
		e.call_member_function("show");
		printf("using e[\"id\"] = %d:\n ", 34);
		e["id"] = 34;
		e.call_member_function("show");
		Any g = e["get_id"]();
		printf("using e[\"get_id\"](): %d\n", g.cast<int>());
		e["show"]();
		a = e["get_id"];
		printf("after f = tencent university:\n");
		f = "tencent university";
		e["show"]();
		printf("after set name = bobby:\n");
		e.set_member_data("name", "bobby");
		e["show"]();
		printf("after call set_name = teddy:\n");
		e.call_member_function("set_name", "teddy");
		e["show"]();
		std::string name;
		Any an = make_any_ref(name);
		e.call_member_function("get_name", an);
		printf("after call get_name, name is %s\n", name.c_str());

		Any gn = get_global_any();
		printf("after call gloabl func(1):\n");
		gn["func"](1);
		gn["global_data"] = 32;
		printf("after set gloabl_data, is %d\n", gn["global_data"].cast<int>());

		printf("global fields and methods:\n");
		std::cout << (*gn.get_type()) << endl;

		Type* tPerson = GetType<Person>();
		tPerson->call_static_method("show_type");

		printf("Person fields and methods:\n");
		std::cout << *tPerson << endl;

		Any n = tPerson->get_static_field("count");
		printf("Person's static field count is %d\n", n.cast<int>());
		
		Any sf = tPerson->get_static_method("show_type");
		sf();

		call_global_method("func", 43);
		Any m = get_global_field("global_data");
		printf("global_data is %d\n", m.cast<int>());
		m = 1970;
		printf("after set global_data, it is %d\n", m.cast<int>());

		Any gf = get_global_method("func");
		if (gf)
		{
			printf("after call global method func:\n");
			gf(45);
		}
		
		Any funcPtr = func;
		funcPtr(1);

		Any lambdaFunc = [](int a, double b) {
			printf("calling lambda a:%d, b:%f\n", a, b);
		};
		lambdaFunc(1, 2.5);

		std::function<void(std::string)> fs = [](std::string input) {
			printf("calling function object: %s\n", input.c_str());
		};
		Any functionObj = fs;
		functionObj("some input");

		Any callableObj = p;
		callableObj("call from any");

		using Traits = inner::invocable_traits<decltype(&Person::add_height)>;
		using U = decltype(&Person::add_height);
		using T = std::decay_t<U>;
		constexpr bool isssame = std::is_same_v<U, T>;
		using r = Traits::return_type;
		using arg = Traits::args_type;
		//Any memFunc = &Person::add_height;
		/*memFunc(0.36);
		p.show();*/

		//using args_type = invocable_traits_a<decltype(&Person::add_height)>;
		
		/*ALua::GetLuaContext()->Initialize();
		lua_State* L = ALua::GetState();
		ALua::RunFile(L, "./Script/test.lua");

		Person* p1 = CreatePerson();
		Person* p2 = CreateStudent();
		printf("Person type is %s, hashcode is %lld\n", typeid(Person).name(), typeid(Person).hash_code());
		printf("Student type is %s, hashcode is %lld\n", typeid(Student).name(), typeid(Student).hash_code());
		printf("p1 type is %s, hashcode is %lld\n", typeid(*p1).name(), typeid(*p1).hash_code());
		printf("p2 type is %s, hashcode is %lld\n", typeid(*p2).name(), typeid(*p2).hash_code());*/
	}
	catch (std::exception& exp)
	{
		std::cout << exp.what();
	}
	return 0;
}